package cn.dengta.context.auth;

import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;

import cn.dengta.common.context.Context;
import cn.dengta.common.web.PackageResolveUtil;
import me.codeplayer.util.StringUtil;

/**
 * 默认的权限策略（用于配置权限码的生成策略等）
 */
public class DefaultPermissionPolicy implements PermissionPolicy {

	@Override
	public PermissionLocator parsePermission(HttpServletRequest request, Class<?> clazz, Method method) {
		PermissionLocator locator = null;
		Permission p = method.getAnnotation(Permission.class);
		// 基于方法的@Permission解析
		if (p != null) {
			locator = parseMenusBasedMethod(clazz, method, request, p);
		}
		// 基于类的@Permission解析
		else if ((p = clazz.getAnnotation(Permission.class)) != null && p.value().length() == 0) {
			String permissionCode = clazz.getName().substring(Context.internal().getActionInfo().getBasePackage().length() + 1);
			locator = new PermissionLocator(method, 0, permissionCode, permissionCode, p.frontCode());
		}
		// 有配置权限码，按照配置的方式解析
		if (p != null && locator == null) {
			locator = new PermissionLocator(method, 0, PackageResolveUtil.getMethodCode(clazz, method), p.value(), p.frontCode());
		}
		return locator;
	}

	protected PermissionLocator parseMenusBasedMethod(Class<?> clazz, Method method, HttpServletRequest request, Permission p) {
		Menu[] menus = p.menus();
		final PermissionLocator locator = new PermissionLocator(method, 0, null, null, p.frontCode());
		boolean hasFrontCode = StringUtil.notEmpty(locator.getFrontCode()); // TODO 后续修改
		String code = hasFrontCode ? locator.getFrontCode() : PackageResolveUtil.getMethodCode(clazz, method);
		if (!hasFrontCode && menus.length > 1) {
			// 如果有@Menus注解，并且有多个@Menu注解
			// 则该方法对应多个菜单、多个权限码：权限码=方法的默认权限码 + 数字后缀(索引)
			// 后缀为 0 时，不追加后缀
			Menu menu;
			for (int i = 0; i < menus.length; i++) {
				if (matchMethodMenu(request, (menu = menus[i]))) {
					setTitle(request, menu);
					// @Permission 如果有配置取配置，否则默认
					int index = menu.suffix().length() > 0 ? Integer.parseInt(menu.suffix()) : i;
					String permissionCode = p.value().length() > 0 ? p.value() : code;
					locator.setMethodCode(index > 0 ? code + "-" + index : code);
					locator.setPermissionCode(index > 0 ? permissionCode + "-" + index : permissionCode);
					locator.setMenuSuffix(index);
					break;
				}
			}
			if (locator.getPermissionCode() == null) {
				throw new PermissionException('[' + method.toString() + "]权限码参数配置有误");
			}
		} else {
			locator.setPermissionCode(p.value().length() > 0 ? p.value() : code);
			locator.setMethodCode(code);
		}
		return locator;
	}

	protected boolean matchMethodMenu(HttpServletRequest request, Menu menu) {
		final String[] args = menu.args(); // 菜单所需校验的额外请求参数的键值对数组
		if (args.length > 0) {
			if ((args.length & 1) != 0) { // 数组长度必须为偶数
				throw new PermissionException("The number of arguments passed in args() must be even!");
			}
			for (int j = 0; j < args.length; j++) {
				String value = request.getParameter(args[j++]);
				// 没有参数值，或不匹配返回 false
				if (StringUtil.isEmpty(value) || (!"*".equals(args[j]) && !value.equals(args[j]))) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 设置标题
	 */
	public static void setTitle(HttpServletRequest request, Menu currentMenu) {
		final String title = currentMenu.name();
		if (title.length() > 0) {
			request.setAttribute(Context.internal().getTitleAttr(), title);
		}
	}

}
